/*!
 * 表单一条龙插件
 * @author chaoqun.lin
 * @updata 2012-5-16
 * @version 1.1.0
 * @about (1)暂时不支持ajax检验(2)暂时不支持动态追加的dom检验
 */
;(function(E){
	E.fn.former = function(settings){
		settings = E.extend({
			subTipTxt: '正在提交',		//提交表单时按钮的文本
			before: null,		//提交前执行操作
			blur: true			//是否支持失焦检测
		}, settings);
		
		//ajax配置
		settings.ajax = E.extend({
			url: '',			//ajax提交URL
			type: 'post',		//ajax提交方式
			async: true,		//ajax提交是否为同步
			success: null,		//成功后执行操作，只有在ajax提交模式下才有用
			error: null		//失败后执行操作，只有在ajax提交模式 下才有用
		},settings.ajax);
		
		//样式控制
		settings.style = E.extend({
			right: '',
			error: '',
			info: '' 	//TODO 保留扩展
		}, settings.style);
		
		//内置正则
		settings.reg = E.extend({
			EMAIL : /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/, //邮箱
			CN : /^[\u4e00-\u9fa5]*$/, //中文
			EN : /^[a-zA-Z]*$/, //字母
			NUM : /^[0-9]*$/, //数字
			SINT : /^[1-9]\d*$/, //正整数
			SFLOAT : /^[1-9]\d*.\d*|0.\d*[1-9]\d*$/, //正浮点数
			MONEY : /^((([1-9]\d*)|0)(\.\d{1,2})?)$/, //money格式
			MPHONE : /^(13|15|18)\d{9}$/, //手机号码
			PHONE : /\d{1,4}-\d{3,4}-\d{7,8}(-\d{1,5})?/, //电话
			COMNAME : /^[\u4e00-\u9fa5\uff08-\uff09\u0028-\u0029]*$/	//公司名或联系人名（不包含特殊特号，全半角括号除外）
		}, settings.reg);
		
		settings.form = this;
		settings.submit = $('#' + settings.submit);
		
		var oF = new E.former(settings);
		return oF;
	};
	E.former = function(settings){	
		var S = this,
			checkNum = 0,								//需要检测的数量
			submitTxt = settings.submit.val() || '',		//提交铵钮文本
			checkFun = [],									//自定义检测函数
		init = function(){
			eventBind();
		},
		/**
		 * 绑定监听事件
		 */
		eventBind = function(){
			//提交按钮监听事件绑定
			settings.submit.bind('click', S.submit);
			//全局不支持失焦，单项支持失焦不生效
			if(settings.blur){
				for(var i in settings.validate){
					settings.validate[i].blur != false && $('#' + i).bind('blur',{param: settings.validate[i], name: i}, check);
				}
			}
		},
		/**
		 * 获取form表单的所有元素，进行数据拼接
		 * 过滤属性 overleap = 'overleap‘的项
		 * @return {Object} 表单数据集合
		 */
		getFormData = function(){
			var elems = $('input:not(:reset,:button,:submit,:image), select, textarea', settings.form);
			var formData = {};
			var name = '';
			for(var i = 0, len = elems.length; i < len; i ++){
				name = elems.eq(i).attr('id') || elems.eq(i).attr('name')
				formData[name] = $.trim(elems.eq(i).val());
			}
			return formData;			
		},
		/**
		 * 检测
		 * @param {JQ Object} 待检JQ对象
		 * @return {Boolean} 检测布尔值返回
		 */
		check = function(obj){
			var rules = obj.data.param.rules;
			var elem = $('#' + obj.data.name);
			var tipElem = getTipDom(obj.data);
			var isOK = true;

			for(var i = 0, len = rules.length; i < len; i ++){
				if(settings.reg[rules[i].rule]){
					isOK = S.checkReg(elem, settings.reg[rules[i].rule]);
				}
				
				switch(rules[i].rule){
					case 'EMPTY':
						isOK = S.checkEmpty(elem);
						break;
					case 'LENGTH':
						isOK = S.checkLength(elem, rules[i].min, rules[i].max);
						break;
					case 'AJAX':
						isOK = S.checkAjax();
						break;
				}
				
				S.showTip(tipElem, isOK, rules[i].txt);
				if(!isOK){
					break;
				}
			}
			return isOK;
		},
		/**
		 * 获取显示提示信息对象
		 * @param {Object} 数据object
		 * @return {JQ Object} 返回JQ对象
		 */
		getTipDom = function(data){
			if(!data.param.tipElem){
				$('#' + data.name).after('<span id="sp' + data.name + '" style="display:none;""></span>');
				return $('#sp' + data.name);	
			}else{
				return $('#' + data.param.tipElem);
			}
		},
		/**
		 * 提交按钮控制
		 * @param {Boolean} 是否禁用
		 */
		submitCtrl = function(isDisabled){
			if(isDisabled){
				submitTxt != '' && settings.submit.val(settings.subTipTxt);
				settings.submit.attr('disabled', true);
			}else{
				settings.submit.attr('disabled', false);
				submitTxt != '' && settings.submit.val(submitTxt);
			}
		},
		/**
		 * ajax提交表单
		 * @param {Object} 表单数据组合
		 */
		ajaxSubmit = function(data){
			typeof settings.before === 'function' && settings.before();
			submitCtrl(true);
			E.ajax({
				type: settings.ajax.type,
				url: settings.ajax.url,
				data: data,
				async: settings.ajax.async,
				success: function(json){
					submitCtrl(false);
					typeof settings.ajax.success === 'function' && settings.ajax.success(json);
				},
				error: function(){
					submitCtrl(false);
					typeof settings.ajax.error === 'function' && settings.ajax.error();
				}
			});
		},
		/**
		 * 传统post提交
		 */
		normalSubmit = function(){
			typeof settings.before === 'function' && settings.before();
			settings.form.submit();
			submitCtrl(true);
		};
		/**
		 * 提交按钮执行全部检测
		 */
		S.submit = function(){
			var obj = {};
			var cklen = 0;
			var ckFunlen = 0;
			checkNum = 0;
			for(var i in settings.validate){
				obj.data = {param: settings.validate[i], name: i};
				if($('#' + i).size() > 0){
					checkNum ++;
					check(obj) && cklen ++;	
				}
			}
			//检测自定义函数
			for(var i = 0; i < checkFun.length; i ++){
				checkFun[i]() == true ? ckFunlen ++ : ckFunlen --;
				//console.log('run check function');
			}
			//如果全部检测通过，提交表单
			if(cklen == checkNum && ckFunlen == checkFun.length){
				if(settings.ajax.url != ''){
					ajaxSubmit(getFormData());
				}else{
					normalSubmit();
				}
			}
		};
		/**
		 * 空检测
		 * @param {JQ Object} 待检测的表单元素
		 * @return {Boolean} 返回布尔值
		 */
		S.checkEmpty = function(obj){
			var val = $.trim(obj.val());
			if(val == ''){
				return false;
			}else{
				return true;
			}
		};
		/**
		 * 长度检测
		 * @param {JQ Object} 待检测的表单元素
		 * @param {Number} 最小长度
		 * @param {Number} 最大长度
		 * @return {Boolean} 返回布尔值
		 */
		S.checkLength = function(obj, min, max){
			var len = $.trim(obj.val()).length;
			if(len > max || len < min){
				return false;
			}else{
				return true;
			} 
		};
		/**
		 * 正则检测
		 * @param {JQ Object} 待检测的表单元素
		 * @param {String} 正则表达式
		 * @return {Boolean} 返回布尔值
		 */
		S.checkReg = function(obj, reg){
			//var reg = new RegExp(reg, regAttr);
			var val = $.trim(obj.val());
			if(reg.test(val)){
				return true;
			}else{
				return false;
			}
		};
		/**
		 * Ajax请求
		 * @param 
		 */
		S.checkAjax = function(opts){
			opts = E.extend({
				type: 'post',
				async: false,
				data: {}
			}, opts);
			$.ajax({
				type: opts.type,
				url: opts.url,
				data: opts.data,
				async: opts.async,
				success: function(){
					
				},
				error: function(){
					alert('网络繁忙，请稍后再试');
				}
			});
		};
		/**
		 * 检测信息显示
		 * @param {Object} 显示信息的JQ对象
		 * @param {Boolean} 显示类型
		 * @param {String} 显示信息
		 */
		S.showTip = function(obj, type, txt){
			switch(type){
				case true:
					if(settings.style.right != ''){
						obj.removeClass(settings.style.error).addClass(settings.style.right);
					}else{
						obj.css('color','');
					}
					obj.html('&nbsp;').show()
					break;
				case false:
					if(settings.style.error != ''){
						obj.removeClass(settings.style.right).addClass(settings.style.error);
					}else{
						obj.css('color','red');
					}
					obj.html(txt).show();
					break;
			}
		};
		/**
		 * 自定义正则检测
		 * @param {String} 调用名称
		 * @param {RegExp} 正则
		 * @return {Object} 返回自身
		 */
		S.addRegRule = function(name, reg){
			settings.reg[name] = reg;
			return S;
		}
		/**
		 * 移除自定义正则检测
		 * @param {String} 调用名称
		 * @return {Object} 返回自身
		 */
		S.removeRegRule = function(name){
			delete settings.reg[name];
			return S;
		}
		/**
		 * 添加检测规则
		 * @param {Object} 规则对象
		 * @return {Object} 返回自身
		 */
		S.addValidate = function(validate){
			for(var i in validate){
				if($('#' + i).size() > 0){
					checkNum ++;
				}
				settings.validate[i] = validate[i];
				if(settings.blur){
					validate[i].blur != false && $('#' + i).bind('blur',{param: validate[i], name: i}, check);
				}
			}
			return S;
		};
		/**
		 * 移除检测规则
		 * @param {String} 规则对象名称
		 * @return {Object} 返回自身
		 */
		S.removeValidate = function(name){
			if(!!settings.validate[name]){
				checkNum --;
				$('#' + name).unbind();
				delete settings.validate[name];
			}
			return S;
		};
		/**
		 * 添加自定义检测
		 * @param {Function} 检测函数
		 * @return {Object} 返回自身
		 */
		S.addMethod = function(fun){
			checkFun.push(fun);
			return S;
		};
		/**
		 * 移除自定义检测
		 * @param {Function} 检测函数
		 * @return {Object} 返回自身
		 */
		S.removeMethod = function(fun){
			for(var i = 0, len = checkFun.length; i < len; i ++){
				console.log(fun == checkFun[i]);
				if(fun == checkFun[i]){
					checkFun.splice(i, 1);
				}
				//console.log(checkFun);
			}
		};
		/**
		 * 手动检测
		 * @param {String} 检测名称
		 * @return {Object} 返回自身
		 */
		S.check = function(name){
			var obj = {};
			obj.data = {name: name, param:settings.validate[name]};
			check(obj);
			return S;
		};
		init();
	};
})(window.jQuery);
